package com.lingx.jt808.service;

import com.lingx.jt808.IJT808Cache;
import com.lingx.jt808.server.netty.JT808Server;
import com.lingx.jt808.server.netty.Utils;
import com.lingx.jt808.utils.CoordinateConversion;
import com.lingx.jt808.zmq.ZmqPubClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class JT808DataService {

    private static final Logger log = LoggerFactory.getLogger(JT808DataService.class.getSimpleName());

    @Resource
    private JT808Server jt808Server;
    @Resource
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void init() {
        List<Map<String, Object>> list = this.jdbcTemplate.queryForList("select * from tgps_car");
        for (Map<String, Object> map : list) {
            IJT808Cache.CACHE_0x0200.put(map.get("id").toString(), map);
        }
        List<Map<String, Object>> list1 = this.jdbcTemplate.queryForList("select id from sys_jt809_chengde");
        for (Map<String, Object> map1 : list1) {
            IJT808Cache.CACHE_jt809_chengde.put(map1.get("id").toString(), map1);
        }
        new Thread(jt808Server).start();
    }

    public int handler0704(String tid, Map<String, Object> map) {
        if (map.get("A01") == null) map.put("A01", 0);
        if (map.get("A02") == null) map.put("A02", 0);
        int status = Integer.parseInt(map.get("status").toString());

        this.jdbcTemplate.update("insert into tgps_data(car_id,acc,location,alarm,status,lat,lng,height,speed,direction,gpstime,systime,mileage) values(?,?,?,?,?,?,?,?,?,?,?,?,?)",
                map.get("tid"), (status & 0b01) > 0 ? "1" : "0", (status & 0b10) > 0 ? "1" : "0", map.get("alarm"), map.get("status"), map.get("lat"), map.get("lng"), map.get("height"), map.get("speed"),
                map.get("direction"), map.get("gpstime"), Utils.getTime(), map.get("A01"));

        if (IJT808Cache.CACHE_jt809_chengde.getIfPresent(tid) != null) {
            ZmqPubClient.sendData(tid);
        }
        return 0;
    }

    public int handler0704Device(String tid, Map<String, Object> map) {
        if (map.get("A01") == null) map.put("A01", 0);
        if (map.get("A02") == null) map.put("A02", 0);
        int status = Integer.parseInt(map.get("status").toString());
        int c = this.jdbcTemplate.update("update tgps_car set acc=?,location=?,alarm=?,status=?,lat=?,lng=?,height=?,speed=?,direction=?,gpstime=?,systime=?,mileage=?,reporttime=? where id=?",
                (status & 0b01) > 0 ? "1" : "0", (status & 0b10) > 0 ? "1" : "0", map.get("alarm"), map.get("status"), map.get("lat"), map.get("lng"), map.get("height"), map.get("speed"), map.get("direction"), map.get("gpstime"), Utils.getTime(), map.get("A01"), Utils.getTime(), map.get("tid"));
        if (c == 0) this.addCar(map);

        return 0;
    }

    /**
     * 上报位置
     *
     * @param tid
     * @param map
     * @param valid
     * @return
     */
    public int handler0200(String tid, Map<String, Object> map, boolean valid) {
        if (valid) {
            if (map.get("A01") == null) map.put("A01", 0);
            if (map.get("A02") == null) map.put("A02", 0);

            IJT808Cache.CACHE_0x0200.put(tid, map);
            int status = Integer.parseInt(map.get("status").toString());
            this.jdbcTemplate.update("insert into tgps_data(car_id,acc,location,alarm,status,lat,lng,height,speed,direction,gpstime,systime,mileage) values(?,?,?,?,?,?,?,?,?,?,?,?,?)",
                    map.get("tid"), (status & 0b01) > 0 ? "1" : "0", (status & 0b10) > 0 ? "1" : "0", map.get("alarm"), map.get("status"), map.get("lat"), map.get("lng"), map.get("height"), map.get("speed"), map.get("direction"), map.get("gpstime"), Utils.getTime(), map.get("A01"));
            int c = this.jdbcTemplate.update("update tgps_car set acc=?,location=?,alarm=?,status=?,lat=?,lng=?,height=?,speed=?,direction=?,gpstime=?,systime=?,mileage=?,reporttime=? where id=?",
                    (status & 0b01) > 0 ? "1" : "0", (status & 0b10) > 0 ? "1" : "0", map.get("alarm"), map.get("status"), map.get("lat"), map.get("lng"), map.get("height"), map.get("speed"), map.get("direction"), map.get("gpstime"), Utils.getTime(), map.get("A01"), Utils.getTime(), map.get("tid"));
            if (c == 0) this.addCar(map);

            Map<String, Object> cache = IJT808Cache.CACHE_ALARM.getIfPresent(tid);
            if (cache == null) {
                cache = this.jdbcTemplate.queryForMap("select limit_speed,limit_speed_enable,limit_stop_time,limit_stop_time_enable,fence from tgps_car where id='" + tid + "'");
                IJT808Cache.CACHE_ALARM.put(tid, cache);
            }

            int limitSpeedEnable = Integer.valueOf(cache.get("limit_speed_enable").toString());
            if (limitSpeedEnable == 1) {
                int limitSpeed = Integer.valueOf(cache.get("limit_speed").toString());
                double currentSpeed = Double.valueOf(map.get("speed").toString());
                if (currentSpeed > limitSpeed) {
                    this.jdbcTemplate.update("insert into tgps_alarm(car_id,type,remark,created_at) values(?,?,?,?)",
                            map.get("tid"), 1, "超速" + currentSpeed, Utils.getTime());
                }
            }

            int limitStopTimeEnable = Integer.valueOf(cache.get("limit_stop_time_enable").toString());
            if (limitStopTimeEnable == 1) {
                if (!cache.containsKey("last_stop_time")) {
                    cache.put("last_stop_time", System.currentTimeMillis() / 1000);
                    cache.put("lat", map.get("lat").toString());
                    cache.put("lng", map.get("lng").toString());
                    IJT808Cache.CACHE_ALARM.put(tid, cache);
                } else {
                    if (!map.get("lat").equals(cache.get("lat"))
                        || !map.get("lng").equals(cache.get("lng"))) {
                        cache.put("last_stop_time", System.currentTimeMillis() / 1000);
                        cache.put("lat", map.get("lat").toString());
                        cache.put("lng", map.get("lng").toString());
                        IJT808Cache.CACHE_ALARM.put(tid, cache);
                    } else {
                        int limitStopTime = Integer.valueOf(cache.get("limit_stop_time").toString());
                        int lastStopTime = Integer.valueOf(cache.get("last_stop_time").toString());
                        if (System.currentTimeMillis() / 1000 - lastStopTime > limitStopTime * 60) {
                            this.jdbcTemplate.update("insert into tgps_alarm(car_id,type,remark,created_at) values(?,?,?,?)",
                                    map.get("tid"), 3, "停车超时", Utils.getTime());
                            cache.put("last_stop_time", System.currentTimeMillis() / 1000);
                            IJT808Cache.CACHE_ALARM.put(tid, cache);
                        }
                    }
                }
            }

            if (cache.get("fence") != null
                 && cache.get("fence").toString().length() > 0) {
                String fence = cache.get("fence").toString();
                String[] fenceList = fence.split(",");
                List<Point2D.Double> pts = new ArrayList<>();
                for (int i = 0; i < fenceList.length; i += 2) {
                    Point2D.Double position = new Point2D.Double(Double.valueOf(fenceList[i]),
                            Double.valueOf(fenceList[i + 1]));
                    pts.add(position);
                }
                Point2D.Double location = new Point2D.Double(Double.valueOf(map.get("lng").toString()),
                        Double.valueOf(map.get("lat").toString()));
                if (pts.size() >= 3
                        && !CoordinateConversion.isPtInPoly(location, pts)) {
                    this.jdbcTemplate.update("insert into tgps_alarm(car_id,type,remark,created_at) values(?,?,?,?)",
                            map.get("tid"), 2, location.x + "," + location.y, Utils.getTime());
                }
            }
        } else {
            this.jdbcTemplate.update("update tgps_car set reporttime=? where id=?",
                    Utils.getTime(), tid);
        }

        if (IJT808Cache.CACHE_jt809_chengde.getIfPresent(tid) != null) {
            ZmqPubClient.sendData(tid);
        }

        return 0;
    }

    /**
     * 车辆注册
     *
     * @param map
     * @return 0：成功；1：车辆已被注册；2：数据库中无该车辆； 3：终端已被注册；4：数据库中无该终端
     */
    public int handle0100(String tid, Map<String, Object> map) {
        try {
            if (this.jdbcTemplate.queryForObject("select count(*) from tgps_car where id=?", Integer.class,
                    tid) == 0) {
                map.put("systemtime", Utils.getTime());
                this.addCar(map);
            } else {
                this.jdbcTemplate.update("update tgps_car set reporttime=? where id=?",
                        Utils.getTime(), tid);
                log.info("handle 0100 has register {}, {}", tid, map.get("p7"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public int handle0002(String tid) {
        try {
            this.jdbcTemplate.update("update tgps_car set reporttime=? where id=?",
                    Utils.getTime(), tid);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (IJT808Cache.CACHE_jt809_chengde.getIfPresent(tid) != null) {
            ZmqPubClient.sendData(tid);
        }
        return 0;
    }

    /**
     * 下发鉴权码
     *
     * @return
     */
    public String get0100Code(String tid) {
        return "1234567890A";
    }

    /**
     * 检查设备上报的鉴权码
     *
     * @param code
     * @return
     */
    public boolean handle0102(String tid, String code) {
        try {
            if (this.jdbcTemplate.queryForObject("select count(*) from tgps_car where id=?", Integer.class,
                    tid) == 0) {
                Map<String, Object> map = new HashMap<>();
                map.put("tid", tid);
                map.put("systemtime", Utils.getTime());
                this.addCar(map);
            } else {
                this.jdbcTemplate.update("update tgps_car set reporttime=? where id=?",
                        Utils.getTime(), tid);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }

    private void addCar(Map<String, Object> map) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date sdate = new Date();
            Date edate = new Date();
            edate.setYear(edate.getYear() + 1);
            String tid = map.get("tid").toString();
            if (map.get("p7") == null || "".equals(map.get("p7").toString().trim())) {
                map.put("p7", tid);
            }
            if (map.get("p5") == null) {
                map.put("p5", tid);
            }
            this.jdbcTemplate.update(
                    "insert into tgps_car(id,carno,zdid,sim,stime,etime,create_time,modify_time,ter_id,reporttime,limit_speed) values(?,?,?,?,?,?,?,?,?,?,?)",
                    tid, map.get("p7"), tid, tid, sdf.format(sdate), sdf.format(edate),
                    map.get("systemtime"), map.get("systemtime"), 0, Utils.getTime(), 120);
            if (this.jdbcTemplate.queryForObject("select count(*) from tgps_group_car where car_id=?", Integer.class,
                    tid) == 0)
                this.jdbcTemplate.update("insert into tgps_group_car(group_id,car_id) values(?,?)", 147, tid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
